
package com.idealighter.game.games.zjh.manager;

import com.alibaba.fastjson.TypeReference;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.core.common.Game;
import com.idealighter.game.games.zjh.struct.ZjhCards;
import com.idealighter.game.games.zjh.struct.ZjhSeat;
import com.idealighter.game.games.zjh.struct.ZjhTable;
import com.idealighter.game.games.zjh.util.ZjhCardsTypeComparator;
import com.idealighter.game.prizepool.manager.PlayerPrizePoolMgrScript;
import com.idealighter.game.prizepool.manager.RoomPrizePoolMgrScript;
import com.idealighter.game.prizepool.struct.control.ZjhControl;
import com.idealighter.game.prizepool.struct.player.PlayerPrizePool;
import com.idealighter.game.prizepool.struct.room.ControlStrategy;
import com.idealighter.game.prizepool.struct.room.RoomPrizePool;
import com.idealighter.utils.code.RandCodeUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 炸金花控制 .
 * 
 * @date 2016年7月13日 上午9:37:12
 *
 */
@Singleton
public class ZjhControlScript {

  private static final Logger LOG = LoggerFactory.getLogger(ZjhControlScript.class);

  // 控制的牌的数量
  public static final int CONTROL_CARDS_NUM = 15;


  @Inject
  private PlayerPrizePoolMgrScript playerPrizePoolMgr;
  @Inject
  private RoomPrizePoolMgrScript roomPrizePoolMgr;

  /**
   * 控制发牌 .
   * 
   * @param table .
   */
  public void controlDealCards(ZjhTable table) {
    List<ZjhSeat> playerSeats = new ArrayList<>();
    List<ZjhSeat> robotSeats = new ArrayList<>();

    for (ZjhSeat s : table.getSeats()) {
      if (s.getPlayerId() > 0) {
        if (s.isRobot()) {
          robotSeats.add(s);
        } else {
          playerSeats.add(s);
        }
      }
    }

    if (robotSeats.size() > 0 && playerSeats.size() > 0) {
      Collections.shuffle(playerSeats);
      Collections.shuffle(robotSeats);
      /**
       * 扎金花只有一个赢家，先判断玩家，再判断机器人 . 控制发牌方法：先将玩家牌排序(从小到大),再根据受控制的玩家输赢和奖池去计算对应的手牌.
       */
      List<ZjhCards> sortedCards = new ArrayList<>();
      int cardIndex = 0;
      for (int i = 0; i < CONTROL_CARDS_NUM; i++) {
        sortedCards.add(
            new ZjhCards(table.getCards().subList(cardIndex, cardIndex += ZjhMgr.PLAYER_CARDS)));
      }

      // 玩家的牌进行排序,从大到小
      sortedCards.sort((my, other) -> ZjhCardsTypeComparator.compare(my, other) ? -1 : 1);

      ZjhSeat winner = null;
      // 玩家最大牌位置
      Integer winnerCardsIndex = null;
      for (ZjhSeat s : playerSeats) {
        Boolean res = null;
        res = playerPrizePoolControl(s);
        if (res == null) {
          res = roomPrizePoolControl(s);
        }
        if (res == null) {
          continue;
        }
        if (res) {
          winner = s;
          // 玩家赢前CONTROL_CARDS_NUM / 2副牌中取
          winnerCardsIndex = RandCodeUtil.random(0, CONTROL_CARDS_NUM / 2);
          // 不能break，playerPrizePoolControl和roomPrizePoolControl会修改seat.control
        } else {
          if (winnerCardsIndex == null) {
            winnerCardsIndex = -1;
          }
        }
      }

      // 没有控制，随机产生赢家
      if (winnerCardsIndex == null) {
        List<ZjhSeat> allSeats = new ArrayList<>();
        allSeats.addAll(playerSeats);
        allSeats.addAll(robotSeats);

        // 随机产生赢牌的玩家
        winner = RandCodeUtil.randomList(allSeats);
        // 随机选出最大的牌
        winnerCardsIndex = RandCodeUtil.random(0, CONTROL_CARDS_NUM / 2);
      } else if (winnerCardsIndex == -1) { // 玩家都是输，确定机器人最大牌位置
        winner = RandCodeUtil.randomList(robotSeats);
        // 机器人赢前3副牌中取
        winnerCardsIndex = RandCodeUtil.random(0, 3);
      }

      int playerCardsIndexTmp = winnerCardsIndex;
      for (ZjhSeat s : table.getSeats()) {
        if (s.getPlayerId() > 0) {
          if (s == winner) {
            dealPlayerCards(s, sortedCards.remove(winnerCardsIndex.intValue()));
          } else if (s.isRobot()) { // 机器人只要比最大牌小就行
            int cardsIndex = RandCodeUtil.random(winnerCardsIndex, sortedCards.size() - 1);
            dealPlayerCards(s, sortedCards.remove(cardsIndex));
          } else { // 玩家的按梯度发
            playerCardsIndexTmp = playerCardsIndexTmp + 1;
            dealPlayerCards(s, sortedCards.remove(playerCardsIndexTmp));
          }
        }
      }
    } else {
      int cardIndex = 0;
      for (ZjhSeat s : table.getSeats()) {
        if (s.getPlayerId() > 0) {
          dealPlayerCards(s,
              new ZjhCards(table.getCards().subList(cardIndex, cardIndex += ZjhMgr.PLAYER_CARDS)));
        }
      }
    }
  }

  /**
   * 个人奖池控制发牌 .
   * 
   * @param seat 座位信息.
   * @param sortedCards .
   * @return null：不受玩家奖池控制，true:赢,false:输
   */
  private Boolean playerPrizePoolControl(ZjhSeat seat) {
    PlayerPrizePool prizePool = playerPrizePoolMgr.prizePool(seat.getPlayerId(), Game.ZJH);

    if (prizePool != null && prizePool.getPrize().get() != 0) {
      ZjhControl control = prizePool.control(new TypeReference<ZjhControl>() {});
      seat.setControl(true);
      // 控制输赢的玩家的输赢标识
      boolean seatWin = RandCodeUtil
          .random(control.getLoseRatio() + control.getWinRatio()) >= control.getLoseRatio();

      return seatWin;
    }

    return null;
  }

  /**
   * 房间控制发牌 .
   * 
   * @param seat 座位信息.
   * @param sortedCards .
   * @return null：不受玩家奖池控制，true:赢,false:输
   */
  private Boolean roomPrizePoolControl(ZjhSeat seat) {
    ZjhTable table = seat.getTable();
    RoomPrizePool roomPrizePool =
        roomPrizePoolMgr.roomPrizePool(seat.getPlayerId(), Game.ZJH, table.getRoom().getId());

    if (roomPrizePool != null) {
      // 房间奖池控制策略
      ControlStrategy strategy = roomPrizePool.abledControlStrategy();
      // 控制输赢的玩家的输赢标识
      boolean seatWin;
      seat.setControl(true);

      if (strategy != null) { // 有控制策略
        // 炸金花控制
        ZjhControl control = strategy.control(new TypeReference<ZjhControl>() {});
        seatWin = RandCodeUtil.random(control.getLoseRatio() + control.getWinRatio()) >= control
            .getLoseRatio();
      } else { // 没有随机输赢
        seatWin = RandCodeUtil.randomBoolean();
      }

      return seatWin;
    }

    return null;
  }

  /**
   * 给玩家发牌 .
   * 
   * @param seat 座位信息.
   * @param cards .
   */
  private void dealPlayerCards(ZjhSeat seat, ZjhCards cards) {
    seat.setCards(cards);
    ZjhTable table = seat.getTable();
    if (table.getMaxCards() == null) {
      table.setMaxCards(cards);
    } else {
      if (ZjhCardsTypeComparator.compare(cards, table.getMaxCards())) {
        table.setMaxCards(cards);
      }
    }
    LOG.info("[炸金花]发送玩家[{}][{}]牌[{}]", seat.getPlayerId(), seat.getPlayerName(), cards.getCards());
  }

  /**
   * 结算奖池 .
   * 
   * @param seat 座位信息.
   * @param winGold . 输赢金币
   */
  public void billPrizePool(ZjhSeat seat, long winGold) {
    if (!billPlayerPrizePool(seat, winGold)) {
      billRoomPrizePool(seat, winGold);
    }
  }

  /**
   * 结算玩家奖池 .
   * 
   * @param seat 座位信息.
   * @param winGold .
   * @return
   */
  private boolean billPlayerPrizePool(ZjhSeat seat, long winGold) {
    PlayerPrizePool prizePool = playerPrizePoolMgr.prizePool(seat.getPlayerId(), Game.ZJH);

    if (prizePool != null && prizePool.getPrize().get() != 0) {
      /*
       * 奖池为：60w,却赢了100w，则奖池达到要求变为0 . 奖池为：-60w,却输了100w，则奖池达到要求变为0
       */
      long prizeGold = prizePool.getPrize().get();

      if (prizeGold > 0) {
        prizeGold = prizeGold - winGold;
        prizeGold = prizeGold < 0 ? 0 : prizeGold;
      } else if (prizeGold < 0) {
        prizeGold = prizeGold - winGold;
        prizeGold = prizeGold > 0 ? 0 : prizeGold;
      }

      prizePool.getPrize().getAndSet(prizeGold);

      return true;
    }

    return false;
  }

  /**
   * 结算玩家奖池 .
   * 
   * @param seat 座位信息.
   * @param winGold .
   * @return
   */
  private boolean billRoomPrizePool(ZjhSeat seat, long winGold) {
    ZjhTable table = seat.getTable();
    RoomPrizePool roomPrizePool =
        roomPrizePoolMgr.roomPrizePool(seat.getPlayerId(), Game.ZJH, table.getRoom().getId());

    if (roomPrizePool != null) {
      long prizeGold = roomPrizePool.getPrize().get();
      prizeGold -= winGold;
      roomPrizePool.getPrize().getAndSet(prizeGold);
      return true;
    }

    return false;
  }
}
